package com.gz.EuchreU.Helpers;

import java.util.ArrayList;

import android.util.Log;

import com.gz.EuchreU.Contants.CardValues;
import com.gz.EuchreU.Contants.GameOptions;
import com.gz.EuchreU.Contants.GameState;
import com.gz.EuchreU.Contants.Suits;
import com.gz.EuchreU.Sprite.Card;

public class Player {
	
	private String mName = "Name";
	private int mPlayerID;
	private float mThinkTime = getThinkTime();
	private boolean mCard = false;
	private static Card mTurnCard;
	private Card mCardInPlay;
	private int mTricksTaken = 0;
	
	ArrayList<Card> mHand = new ArrayList<Card>();
	
	public Player(int pPlayerID){
		mPlayerID = pPlayerID;
	}
	
	public static Card GetTurnCard(){
		return mTurnCard;
	}
	
	public void Clear(){
		mThinkTime = getThinkTime();
		mHand.clear();
		mTricksTaken = 0;
	}
	
	public void AddTrickWon(){
		mTricksTaken++;
	}
	
	public void AddCard(Card pCard){
		log("Adding card " + pCard.ToString());
		mHand.add(pCard);
		pCard.MoveToHand(mPlayerID,mHand.size(),true);
	}
		
	public boolean IsPartner(int pPlayerID){
		return pPlayerID == mPlayerID - 2 || pPlayerID == mPlayerID + 2;
	}
	
	public boolean IsPartnerWinningTrick(){
		if(GameState.GetCurrentTrickCount() > 1){
			return IsPartner(GameState.GetPlayerWinningTrick());
		}
		else return false;
	}
	
	public boolean IsPartnerCall(){
		return IsPartner(GameState.GetOrderedPlayerID());
	}
	
	public boolean IsMyCall(){
		return mPlayerID == GameState.GetOrderedPlayerID();
	}
	
	public float getThinkTime(){
		switch(GameOptions.GetIntOption(GameOptions.PREF_INT_GAME_SPEED)){
		case 1:
			return 1f;
		case 2:
			return .5f;
		case 3:
			return .1f;
		case 4:
			return .01f;
		default:
			return .3f;
		}
	}
	
	public void OrganizeHand(){
		int index = 0;
		
//		ArrayList<Card> tempCards = new ArrayList<Card>();

		for (int i = 0; i < 4; i++) {
			ArrayList<Card> suit = GetCardsInSuit(i);
			for(Card card: suit){
				card.MoveToHand(mPlayerID, index, true);
				index++;
			}
		}
		
	}
	
	public ArrayList<Card> GetCardsInSuit(int pSuitID){
		ArrayList<Card> aReturn = new ArrayList<Card>();
		
		for(Card card : mHand){
			if(card.IsSuit(pSuitID)){
				aReturn.add(card);
			}
		}
		
		return aReturn;
	}
	
	public void Update(float pSeconds){
		if(mCard){
			if(mCardInPlay != null){
				if(mCardInPlay.IsMoving() == false){
					mCard = false;
					GameState.PlayCard(mCardInPlay);
				}
			}
			else mCard = false;
		}
		else if(GameState.IsHuman(mPlayerID)){
			switch (GameState.getGameState()) {
			case GameState.TURN_CARD_UP:
			case GameState.TURN_CARD_DOWN:
			case GameState.PLAYING_TRICKS:
//				log("Waiting for human");
				
				if(GameOptions.GetBoolOption(GameOptions.PREF_BOOL_AUTO_PLAY_LAST)){
					if(mHand.size() == 1){
						log("Auto play human last trick. ");
						PlayCard(0);
					}
				}
				else if(GameOptions.GetBoolOption(GameOptions.PREF_BOOL_AUTO_PLAY_31) && mHand.size() == 1){
					if(GameState.GetRedTricks() == 3 || GameState.GetBlueTricks() == 3){
						log("Auto play human due to 3-1 score");
						PlayCard(0);
					}
				}
				
				break;
			case GameState.TRUMP_CALLED:
				OrganizeHand();
				break;
			default:
				break;
			}
		}
		else
		{
			//AI stuff!
			if(GameState.getCurrentPlayer() == mPlayerID){
				//My turn
				if(GameState.IsHandDecidedEarly()){
					log("Trick is already set, playing fast");
					PlayCardInstant(0);
				}
				else if(mThinkTime <= 0){
					mThinkTime = getThinkTime();
					switch (GameState.getGameState()) {
					case GameState.TURN_CARD_UP:
						if(IsPartner(GameState.getDealer()) && !GameOptions.GetBoolOption(GameOptions.PREF_BOOL_DEALER_P_ORDER)){
							log("P is dealer... have to pass");
							GameState.Pass();
						}
						
						else if(IsPickUpHand()){
							log("Pick it up! " + GameState.getDealer() + "-" + GameState.GetTurnCard().ToString());
							GameState.PickUp(IsLonerHand());
						}
						else{
							log("Pass...");
							GameState.Pass();
						}
						break;
					case GameState.TURN_CARD_DOWN:
						if(IsCallSuitHand()){
							log("Calling suit.");
							GameState.CallSuit(GetCallSuitID(),IsLonerHand());
						}
						else{
							if(mPlayerID == GameState.getDealer() && GameOptions.GetBoolOption(GameOptions.PREF_BOOL_STD)){
								int forcedCall = GetCallSuitID();
								log("Forced to call suit... " + forcedCall);
								GameState.CallSuit(forcedCall,IsLonerHand());
							}
							else{
								log("Pass(on call suit)...");
								GameState.Pass();	
							}
						}
						
						break;
					case GameState.DISCARDING:
						Discard(AIGetDiscard());
						break;
					case GameState.PLAYING_TRICKS:
						Card cardToPlay = AIGetCardToPlay();
						log("Playing card - " + cardToPlay.ToString() + " - " + cardToPlay.GetCardHandValue());
						PlayCard(cardToPlay);
						break;
					default:
							break;
					}
				}
				else{
					mThinkTime -= pSeconds;
				}
			}
		}
	}

//	public static final int VALUES_RIGHT_BAUER = 40;
//	public static final int VALUES_LEFT_BAUER = 35;
//	public static final int VALUES_TRUMP_BONUS = 20;
//	public static final int VALUES_FOLLOW_BONUS = 10;
	
	public boolean CanPlayCard(Card pCard){		
		if(GameState.getGameState() == GameState.DISCARDING && GameState.getDealer() == mPlayerID){
			return true;
		}
		else if(GameState.GetCurrentTrickCount() == 0){
			return true;
		}
		else
		{
			if(pCard.IsSameSuitAsLead()){
				return true;
			}
			else{
				if(CanFollowSuit()){
					return false;
				}
				else {
					return true;
				}
			}
		}
	}
	
	private boolean IsCallSuitHand(){
		log("Checking for call suit");
		
		if(GameOptions.GetBoolOption(GameOptions.PREF_BOOL_AI_ALWAYS_PASSES)){
			log("Not a call suit hand... AI always passes");
			return false;
		}
		
		int[] suitHandValue = GetSuitHandValues();
		
		for (int i = 0; i < suitHandValue.length; i++) {
			if(suitHandValue[i] > 100){
				return true;
			}
		}
		
		return false;
	}
	
	private boolean IsLonerHand(){
		if(GameOptions.GetBoolOption(GameOptions.PREF_BOOL_LONER)){
			return GetHandValue() > 110;
		}
		else return false;
	}
	
	private int GetCallSuitID(){
		boolean blnNone = GameOptions.GetBoolOption(GameOptions.PREF_BOOL_CALL_NO_TRUMP);
		log("Checking for call suit. CallNone=" + blnNone);
		int[] suitHandValue = GetSuitHandValues();
		
		int highID = -1;
		int highValue = 0;
		
		for (int i = 0; i < suitHandValue.length; i++) {
			if(blnNone){
				if(suitHandValue[i] > 100){
					highID = i;
				}
			}
			else
			{
				if(suitHandValue[i] > highValue){
					highID = i;
					highValue = suitHandValue[i];
				}
			}
			
		}
		
		return highID;
	}
	
	private int[] GetSuitHandValues(){
		int[] suitHandValue = new int[4];
		suitHandValue[0] = 0;
		suitHandValue[1] = 0;
		suitHandValue[2] = 0;
		suitHandValue[3] = 0;
		
		for(Card card: mHand){
			int[] suitValues = card.GetPotentialCardValues();
			for (int i = 0; i < suitValues.length; i++) {
				suitHandValue[i] += suitValues[i];
			}
		}
		
		return suitHandValue;
	}	
	
	private boolean IsPickUpHand(){
		int handVal = 0;
		
		if(GameOptions.GetBoolOption(GameOptions.PREF_BOOL_AI_ALWAYS_PASSES)){
			log("Not a pickup hand - AI always passes");
			return false;
		}
		
		handVal = GetHandValue();
		
		log("Hand value for pickup: " + handVal);
	
		
		return handVal > 100;
	}
	
	private int GetHandValue(){
		int handVal = 0;
		
		for(Card card: mHand){
			handVal += card.GetPotentialCardValue(GameState.GetTurnCard().GetSuitID());
		}
		
		if(GameState.getDealer() == mPlayerID){
			handVal += 1.25*GameState.GetTurnCard().GetPotentialCardValue(GameState.GetTurnCard().GetSuitID());
		}
		else if(IsPartner(GameState.getDealer())){
			handVal += GameState.GetTurnCard().GetPotentialCardValue(GameState.GetTurnCard().GetSuitID());
		}
		else{
			handVal -= GameState.GetTurnCard().GetPotentialCardValue(GameState.GetTurnCard().GetSuitID());
		}
		
		return handVal;
	}
	
	private Card AIGetDiscard(){
		return mHand.get(0);
	}
	
	private Card AIGetCardToPlay(){
		log("AI Thinking. " + GameState.GetTrickString());
		
		if(mHand.size() == 1){
			log("Playing my only card");
			return mHand.get(0);
		}
		else{
			log("AI play. Skill: " + GetAISkillLevel());
			switch(GetAISkillLevel()){
			case 1:
				return AIGetCardToPlay_Easy_Passive();
			case 2:
				return AIGetCardToPlay_Easy_Aggressive();
			case 3:
				return AIGetCardToPlay_Normal();
			case 4:
				return AIGetCardToPlay_Hard();
			default:
				return AIGetCardToPlay_Normal();
			}
		}
	}
	
	private int GetAISkillLevel(){
		switch(mPlayerID){
		case 0: //North
			return GameOptions.GetIntOption(GameOptions.PREF_INT_P_SKILL);
		case 1: //East
			return GameOptions.GetIntOption(GameOptions.PREF_INT_O_RIGHT_SKILL);
		case 3: //West
			return GameOptions.GetIntOption(GameOptions.PREF_INT_O_LEFT_SKILL);
		default:
			return 3;
		}
		
		
	}
	
	private Card AIGetCardToPlay_Easy_Passive(){
		if(GameState.GetCurrentTrickCount() == 0){
			log("My lead... - Easy");
			return GetLowCard();
		}
		else if(CanFollowSuit()){
			log("I have to follow suit - Easy");
			return GetLowFollowSuitCard();
		}
		else{
			log("Stupidly play low card - Easy");
			return GetLowCard();
		}
	}
	
	private Card AIGetCardToPlay_Easy_Aggressive(){
		if(GameState.GetCurrentTrickCount() == 0){
			log("My lead... - Easy Agg");
			if(IsMyCall() || IsPartnerCall()){
				log("We ordered up");
				if(HasLeft() || HasRight()){
					log("Have a Jack. leading high card - Easy Agg");
					return GetHighTrumpCard();
				}
				else if(HasAnyAce()){
					log("No Jacks. leading ace - Easy Agg");
					return GetAnyAce();
				}
				else{
					log("No Jacks or aces. trying to short suit. - Easy Agg");
					return GetShortSuitOrLowCard();
				}
			}
			else if(HasNonTrumpAce()){
				log("We didn't order up. Lead non trump ace - Easy Agg");
				return GetNonTrumpAce();
			}
			else return GetHighCard();
		}
		else if(CanFollowSuit()){
			log("I have to follow suit - I don't pay attention to my p - Easy Agg");
			
			if(CanWinTrick()){
				log("Follow suit - can win go high. - Easy Agg");
				return GetHighFollowSuitCard();	
			}
			else {
				log("Follow suit - cant win go low. - Easy Agg");
				return GetLowFollowSuitCard();
			}
		}
		else if(CanTrump()){
			log("I dont need to follow suit... TRUMP!? - Easy Agg");
			//TODO: Consider cards in play
			if(CanWinTrick()){
				log("I can win.");				
				if(IsTrumpInTrick()){
					log("already trump... playing high trump - Easy Agg");
					return GetHighTrumpCard();
				}
				else{
					log("first trump, playing lowest - Easy Agg");
					return GetLowTrumpCard();
				}
			}
			else{
				log("I can't win... throw off - Easy Agg");
				return GetThrowOffCard();
			}
		}
		else{
			log("Can't trump, Can't follow... Throw low - Easy Agg");
			return GetLowCard();
		}
	}
	
	private Card AIGetCardToPlay_Normal(){
		if(GameState.GetCurrentTrickCount() == 0){
			log("My lead... - Normal");
			if(IsMyCall() || IsPartnerCall()){
				log("We ordered up - Normal");
				if(HasLeft() || HasRight()){
					log("Have a Jack. leading high card - Normal");
					return GetHighTrumpCard();
				}
				else if(HasAnyAce()){
					log("No Jacks. leading ace - Normal");
					return GetAnyAce();
				}
				else{
					log("No Jacks or aces. trying to short suit. - Normal");
					return GetShortSuitOrLowCard();
				}
			}
			else if(HasNonTrumpAce()){
				log("We didn't order up. Lead non trump ace - Normal");
				return GetNonTrumpAce();
			}
			else return GetShortSuitOrLowCard();
		}
		else if(CanFollowSuit()){
			log("I have to follow suit - Normal");
			if(IsPartnerWinningTrick()){
				//TODO: Consider trump... aces... etc
				return GetLowFollowSuitCard();
			}
			else{
//				if(GameState.CurrentTrickCount() == 3)
//				{
//					return GetLowCardInSuitAboveValue(GameState.GetHighCardInTrick().GetCardHandValue());
//				}
				if(CanWinTrick()){
					log("Follow suit - can win go high. - Normal");
					return GetHighFollowSuitCard();	
				}
				else {
					log("Follow suit - cant win go low. - Normal");
					return GetLowFollowSuitCard();
				}
				
				
			}
		}
		else if(CanTrump()){
			log("I dont need to follow suit... TRUMP!? - Normal");
			//TODO: Consider cards in play
			if(IsPartnerWinningTrick()){
				log("Partner is winning... i will throw off - Normal");
				return GetThrowOffCard();
			}
			else if(CanWinTrick()){
				log("I can win. - Normal");
//				if(GameState.CurrentTrickCount() == 3)
//				{
					//return GetLowCardAboveValue(GameState.GetHighCardInTrick().GetCardHandValue());
//				}
//				else{	
//					return GetHighTrumpCard();
//				}
				
				if(IsTrumpInTrick()){
					log("already trump... playing high trump - Normal");
					return GetHighTrumpCard();
				}
				else{
					log("first trump, playing lowest - Normal");
					return GetLowTrumpCard();
				}
			}
			else{
				log("I can't win... throw off - Normal");
				return GetThrowOffCard();
			}
		}
		else{
			log("Can't trump, Can't follow... Throw low - Normal");
			return GetLowCard();
		}
	}
	
	private Card AIGetCardToPlay_Hard(){
		
		//TODO: Make a smart AI...
		log("Hard skill is set to return Normal...");
		return AIGetCardToPlay_Normal();
	}
	
	public int GetTrickCount(){
		return mTricksTaken;
	}
	
	private void PlayCard(int pCardID){
		PlayCard(mHand.get(pCardID));
	}
	
	public void HumanPlayCard(Card pCard){
		switch(GameState.getGameState()){
		case GameState.PLAYING_TRICKS:
			PlayCard(pCard);
			break;
		case GameState.DISCARDING:
			Discard(pCard);
			break;
			default:
				break;
		}
	}
	
	private void PlayCard(Card pCard){
		pCard.MoveToPlay();
		RemoveCard(pCard);
		mCardInPlay = pCard;
		mCard = true;
		
	}
		
	private void PlayCardInstant(int pCardID){
		mCard = false;
		log("Playing instant " + pCardID);
		mHand.get(pCardID).MoveToPlay();
		GameState.PlayCard(mHand.get(pCardID));
		mHand.remove(pCardID);
	}
	
	public void Discard(Card pCard){
		log("Discarding " + pCard.ToString());
		pCard.MoveToDiscard();
		if(mHand.contains(pCard))mHand.remove(pCard);
		GameState.Discard();
	}
	
	private void RemoveCard(Card pCard){
		log("Removing Card " + pCard.ToString());
		if(mHand.contains(pCard)){
			mHand.remove(pCard);
			log("Removed:" + pCard.ToString());
		}
		else log("Card doesn't exits, can't remove - " + pCard.ToString());
	}
	
	public boolean CanFollowSuit(){
		boolean blnReturn = false;
		for(Card card: mHand){
			if(card.IsSameSuitAsLead()){
				blnReturn = true;
			}
		}
		
		return blnReturn;
	}
	
	public boolean IsTrumpInTrick(){
		if(GameState.GetCurrentTrickCount() == 0)return false;
		else{
			for (int i = 0; i < GameState.GetCurrentTrick().length; i++) {
				if(GameState.GetCurrentTrick()[i] == null){
					
				}
				else if(GameState.GetCurrentTrick()[i].IsTrump()){
					return true;
				}
			}
		}
		return false;
	}
	
	public boolean CanWinTrick(){
		if(GameState.GetCurrentTrickCount() == 0)return true;
		else if(GameState.GetLeadCard().IsRight())return false;
		else{
			if(CanFollowSuit()){
				return GetHighFollowSuitCard().GetCardHandValue() > GameState.GetLeadCard().GetCardHandValue();
			}
			else return GetHighCard().GetCardHandValue() > GameState.GetLeadCard().GetCardHandValue();
		}
	}
	
	public Card GetHighFollowSuitCard(){
		int highValue = -1;
		Card highCard = GetLowFollowSuitCard();
		for(Card card: mHand){
			if(card.IsSameSuitAsLead()){
				if(card.GetCardHandValue() > highValue){
					highValue = card.GetCardHandValue();
					highCard = card; 
				}
			}
		}
		return highCard;
	}
	
	public Card GetLowFollowSuitCard(){
		int lowValue = 99;
		Card lowCard = null;
		for(Card card: mHand){
			if(card.IsSameSuitAsLead()){
				if(card.GetCardHandValue() < lowValue){
					lowValue = card.GetCardHandValue();
					lowCard = card; 
				}
			}
		}
		return lowCard;
	}
	
	public Card GetLowCardInSuit(int pSuitID){
		int lowValue = 99;
		Card lowCard = GetLowCard();
		for(Card card: mHand){
			if(card.IsSuit(pSuitID)){
				if(card.GetCardHandValue() < lowValue){
					lowValue = card.GetCardHandValue();
					lowCard = card; 
				}
			}
		}
		return lowCard;
	}
	
	public Card GetLowCardAboveValue(int pCardValue){
		Card lowCard = GetLowFollowSuitCard();
		for(Card card: mHand){
			if(card.GetCardHandValue() > pCardValue){
				if(card.GetCardHandValue() < lowCard.GetCardHandValue()){
					lowCard = card; 
				}
			}
		}
		return lowCard;
	}
	
	public Card GetHighTrumpCard(){
		int highValue = -1;
		Card highCard = null;
		for(Card card: mHand){
			if(card.IsTrump()){
				if(card.GetCardHandValue() > highValue){
					highValue = card.GetCardHandValue();
					highCard = card; 
				}
			}
		}
		return highCard;
	}
	
	public Card GetLowTrumpCard(){
		int lowValue = 99;
		Card lowCard = null;
		for(Card card: mHand){
			if(card.IsTrump()){
				if(card.GetCardHandValue() < lowValue){
					lowValue = card.GetCardHandValue();
					lowCard = card; 
				}
			}
		}
		return lowCard;
	}
	
	public Card GetHighCard(){
		int highValue = -1;
		Card highCard = null;
		for(Card card: mHand){
			if(card.GetCardHandValue() > highValue){
				highValue = card.GetCardHandValue();
				highCard = card; 
			}
		}
		
		log("My high card is " + highCard.ToString());
		
		return highCard;
	}
	
	public Card GetLowCard(){
		int lowValue = 99;
		Card lowCard = null;
		for(Card card: mHand){
			if(lowCard == null){
				lowCard = card;
				lowValue = card.GetCardHandValue();
			}
			else if(card.GetCardHandValue() < lowValue){
				lowValue = card.GetCardHandValue();
				lowCard = card; 
			}
		}
		
		if(lowCard == null)return mHand.get(0);
		
		return lowCard;
	}
	
	public boolean HasLeft(){
		for(Card card: mHand){
			if(card.IsLeft()){
				return true;
			}
		}
		return false;
	}
	
	public boolean HasRight(){
		for(Card card: mHand){
			if(card.IsRight()){
				return true;
			}
		}
		return false;
	}
	
	public boolean HasAnyAce(){
		for(Card card: mHand){
			if(card.GetValueID() == CardValues.ACE){
				return true;
			}
		}
		return false;
	}
	
	public Card GetAnyAce(){
		for(Card card: mHand){
			if(card.GetValueID() == CardValues.ACE){
				return card;
			}
		}
		return null;
	}
	
	public boolean HasNonTrumpAce(){
		for(Card card: mHand){
			if(card.GetValueID() == CardValues.ACE && !card.IsTrump()){
				return true;
			}
		}
		return false;
	}
	
	public Card GetNonTrumpAce(){
		for(Card card: mHand){
			if(card.GetValueID() == CardValues.ACE && !card.IsTrump()){
				return card;
			}
		}
		return null;
	}
	
	public boolean CanTrump(){
		boolean blnReturn = false;
		for(Card card: mHand){
			if(card.IsTrump()){
				return true;
			}
		}
		return blnReturn;
	}
	
	public Card GetThrowOffCard(){
		if(CanTrump() && CanShortSuit()){
			//There is a reason to short suit
			return GetShortSuitCard();
		}
		else{
			//No reason to short suit
			return GetLowCard();
		}
	}
	
	public boolean CanShortSuit(){
		if(CanFollowSuit())return false;
		else{
			for (int i = 0; i < 4; i++) {
				if(Suits.getTrumpID() != i){
					if(GetSuitCount(i) == 1){
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	private Card GetShortSuitOrLowCard(){
		Card card = GetShortSuitCard();
		if(card == null){
			card = GetLowCard();
		}
		return card;
	}
	
	private Card GetShortSuitCard(){
		boolean[] shortSuit = new boolean[4];
		for (int i = 0; i < shortSuit.length; i++) {
			if(Suits.getTrumpID() == i){
				shortSuit[i] = false;
			}
			else{
				shortSuit[i] = GetSuitCount(i) == 1;
			}
		}
		
		Card lowCard = null;
		for (int i = 0; i < shortSuit.length; i++) {
			if(shortSuit[i]){
				Card card = GetLowCardInSuit(i);
				if(lowCard == null)lowCard = card;
				else if(card.GetCardHandValue() < lowCard.GetCardHandValue()){
					lowCard = card;
				}
			}
		}
		
		return lowCard;
	}
	
	private int GetSuitCount(int SuitID){
		int intReturn = 0;
		for(Card card: mHand){
			if(card.IsLeft() && Suits.getTrumpID() == SuitID)intReturn++;
			else if(card.GetSuitID() == SuitID)intReturn++;
		}
		
		return intReturn;
	}
	
	private void log(String msg){
		Log.d("P:" + HandToString(),msg);
	}
	
	private String HandToString(){
		String strReturn = mPlayerID + "-";
		
		for(Card card : mHand){
			strReturn += card.ToShortString() + "__";
		}
		return strReturn.substring(0, strReturn.length() - 1);
	}
	
}


